From db2eb85e4af9d8f191fe1ade53ec85a94b326c9f Mon Sep 17 00:00:00 2001 From: Rui Matos Date: Wed, 1 Feb 2012 17:59:23 +0000 Subject: [PATCH] x11: Cancel _NET_WM_MOVERESIZE if we get a matching ButtonRelease This implements the following part of the EWMH spec: "The special value _NET_WM_MOVERESIZE_CANCEL also allows clients to cancel the operation by sending such message if they detect the release themselves (clients should send it if they get the button release after sending the move resize message, indicating that the WM did not get a grab in time to get the release)." In particular, it fixes the case of clicking widgets that use gdk_window_begin_[resize|move]_drag*() and the click "sticking", i.e. the mouse button getting released but the resize or move operation remaining in effect. https://bugzilla.gnome.org/show_bug.cgi?id=669208 --- gdk/x11/gdkdisplay-x11.h | 2 + gdk/x11/gdkwindow-x11.c | 150 +++++++++++++++++++++++++++------------ 2 files changed, 106 insertions(+), 46 deletions(-) diff --git a/gdk/x11/gdkdisplay-x11.h b/gdk/x11/gdkdisplay-x11.h index 7fdb05e231..0c868ed2a1 100644 --- a/gdk/x11/gdkdisplay-x11.h +++ b/gdk/x11/gdkdisplay-x11.h @@ -131,6 +131,8 @@ struct _GdkX11Display GdkWindow *active_offscreen_window; GSList *error_traps; + + gint wm_moveresize_button; }; struct _GdkX11DisplayClass diff --git a/gdk/x11/gdkwindow-x11.c b/gdk/x11/gdkwindow-x11.c index 5d3df85cc2..6084aa761c 100644 --- a/gdk/x11/gdkwindow-x11.c +++ b/gdk/x11/gdkwindow-x11.c @@ -4020,22 +4020,30 @@ gdk_window_x11_set_static_gravities (GdkWindow *window, return TRUE; } +/* From the WM spec */ +#define _NET_WM_MOVERESIZE_SIZE_TOPLEFT 0 +#define _NET_WM_MOVERESIZE_SIZE_TOP 1 +#define _NET_WM_MOVERESIZE_SIZE_TOPRIGHT 2 +#define _NET_WM_MOVERESIZE_SIZE_RIGHT 3 +#define _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT 4 +#define _NET_WM_MOVERESIZE_SIZE_BOTTOM 5 +#define _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT 6 +#define _NET_WM_MOVERESIZE_SIZE_LEFT 7 +#define _NET_WM_MOVERESIZE_MOVE 8 /* movement only */ +#define _NET_WM_MOVERESIZE_SIZE_KEYBOARD 9 /* size via keyboard */ +#define _NET_WM_MOVERESIZE_MOVE_KEYBOARD 10 /* move via keyboard */ +#define _NET_WM_MOVERESIZE_CANCEL 11 /* cancel operation */ + static void -wmspec_moveresize (GdkWindow *window, - gint direction, - GdkDevice *device, - gint button, - gint root_x, - gint root_y, - guint32 timestamp) +wmspec_send_message (GdkDisplay *display, + GdkWindow *window, + gint root_x, + gint root_y, + gint action, + gint button) { - GdkDisplay *display = GDK_WINDOW_DISPLAY (window); - XClientMessageEvent xclient; - /* Release passive grab */ - gdk_device_ungrab (device, timestamp); - memset (&xclient, 0, sizeof (xclient)); xclient.type = ClientMessage; xclient.window = GDK_WINDOW_XID (window); @@ -4044,49 +4052,70 @@ wmspec_moveresize (GdkWindow *window, xclient.format = 32; xclient.data.l[0] = root_x; xclient.data.l[1] = root_y; - xclient.data.l[2] = direction; + xclient.data.l[2] = action; xclient.data.l[3] = button; xclient.data.l[4] = 1; /* source indication */ XSendEvent (GDK_DISPLAY_XDISPLAY (display), GDK_WINDOW_XROOTWIN (window), False, - SubstructureRedirectMask | SubstructureNotifyMask, - (XEvent *)&xclient); + SubstructureRedirectMask | SubstructureNotifyMask, + (XEvent *)&xclient); } -typedef struct _MoveResizeData MoveResizeData; +static gboolean +handle_wmspec_button_release (GdkDisplay *display, + XEvent *xevent) +{ + GdkX11Display *display_x11 = GDK_X11_DISPLAY (display); + GdkWindow *window; -struct _MoveResizeData +#if defined (HAVE_XGENERICEVENTS) && defined (XINPUT_2) + XIEvent *xiev = (XIEvent *) xevent->xcookie.data; + XIDeviceEvent *xidev = (XIDeviceEvent *) xiev; + + if (xevent->xany.type == GenericEvent) + window = gdk_x11_window_lookup_for_display (display, xidev->event); + else +#endif + window = gdk_x11_window_lookup_for_display (display, xevent->xany.window); + + if (display_x11->wm_moveresize_button != 0 && window != NULL) + { + if ((xevent->xany.type == ButtonRelease && + xevent->xbutton.button == display_x11->wm_moveresize_button) +#if defined (HAVE_XGENERICEVENTS) && defined (XINPUT_2) + || + (xevent->xany.type == GenericEvent && + xiev->evtype == XI_ButtonRelease && + xidev->detail == display_x11->wm_moveresize_button) +#endif + ) + { + display_x11->wm_moveresize_button = 0; + wmspec_send_message (display, window, 0, 0, _NET_WM_MOVERESIZE_CANCEL, 0); + return TRUE; + } + } + + return FALSE; +} + +static void +wmspec_moveresize (GdkWindow *window, + gint direction, + GdkDevice *device, + gint button, + gint root_x, + gint root_y, + guint32 timestamp) { - GdkDisplay *display; - - GdkWindow *moveresize_window; - GdkWindow *moveresize_emulation_window; - gboolean is_resize; - GdkWindowEdge resize_edge; - GdkDevice *device; - gint moveresize_button; - gint moveresize_x; - gint moveresize_y; - gint moveresize_orig_x; - gint moveresize_orig_y; - gint moveresize_orig_width; - gint moveresize_orig_height; - GdkWindowHints moveresize_geom_mask; - GdkGeometry moveresize_geometry; - Time moveresize_process_time; - XEvent *moveresize_pending_event; -}; + GdkDisplay *display = GDK_WINDOW_DISPLAY (window); -/* From the WM spec */ -#define _NET_WM_MOVERESIZE_SIZE_TOPLEFT 0 -#define _NET_WM_MOVERESIZE_SIZE_TOP 1 -#define _NET_WM_MOVERESIZE_SIZE_TOPRIGHT 2 -#define _NET_WM_MOVERESIZE_SIZE_RIGHT 3 -#define _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT 4 -#define _NET_WM_MOVERESIZE_SIZE_BOTTOM 5 -#define _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT 6 -#define _NET_WM_MOVERESIZE_SIZE_LEFT 7 -#define _NET_WM_MOVERESIZE_MOVE 8 + /* Release passive grab */ + gdk_device_ungrab (device, timestamp); + GDK_X11_DISPLAY (display)->wm_moveresize_button = button; + + wmspec_send_message (display, window, root_x, root_y, direction, button); +} static void wmspec_resize_drag (GdkWindow *window, @@ -4145,6 +4174,30 @@ wmspec_resize_drag (GdkWindow *window, wmspec_moveresize (window, direction, device, button, root_x, root_y, timestamp); } +typedef struct _MoveResizeData MoveResizeData; + +struct _MoveResizeData +{ + GdkDisplay *display; + + GdkWindow *moveresize_window; + GdkWindow *moveresize_emulation_window; + gboolean is_resize; + GdkWindowEdge resize_edge; + GdkDevice *device; + gint moveresize_button; + gint moveresize_x; + gint moveresize_y; + gint moveresize_orig_x; + gint moveresize_orig_y; + gint moveresize_orig_width; + gint moveresize_orig_height; + GdkWindowHints moveresize_geom_mask; + GdkGeometry moveresize_geometry; + Time moveresize_process_time; + XEvent *moveresize_pending_event; +}; + static MoveResizeData * get_move_resize_data (GdkDisplay *display, gboolean create) @@ -4324,6 +4377,9 @@ _gdk_x11_moveresize_handle_event (XEvent *event) GdkDisplay *display = gdk_x11_lookup_xdisplay (event->xany.display); MoveResizeData *mv_resize = get_move_resize_data (display, FALSE); + if (handle_wmspec_button_release (display, event)) + return TRUE; + if (!mv_resize || !mv_resize->moveresize_window) return FALSE; @@ -4405,6 +4461,8 @@ _gdk_x11_moveresize_configure_done (GdkDisplay *display, XEvent *tmp_event; MoveResizeData *mv_resize = get_move_resize_data (display, FALSE); + GDK_X11_DISPLAY (display)->wm_moveresize_button = 0; + if (!mv_resize || window != mv_resize->moveresize_window) return FALSE; -- 2.30.2